package jp.co.jspnet.yahata.osgi.eventhandler.twitter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Properties;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;

import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;

public class EventHandlerImpl implements EventHandler {

    public static final String PROP_FILE_NAME = "eventhandler_twitter.properties";
    public static final File PROP_FILE = new File(PROP_FILE_NAME);
    public static final String PROP_KEY_SCREEN_NAME =
            "jp.co.jspnet.yahata.osgi.eventhandler.twitter.screenName";
    public static final String PROP_KEY_PASSWORD =
            "jp.co.jspnet.yahata.osgi.eventhandler.twitter.password";

    void checkStatus() throws Exception {
        // 設定ファイルの存在をチェックする。
        // 設定ファイルがない場合はfalseを返す。
        if (PROP_FILE.exists() != true) {
            throw new IllegalStateException(
                    "Could not get twitter setting file. file path = " + PROP_FILE.getAbsolutePath());
        }
    }

    Dictionary getServiceProperties() {
        String[] topics = {
                EventConstants.EVENT_TOPIC, "org/osgi/framework/BundleEvent/*"};
        Hashtable serviceProperties = new Hashtable();
        serviceProperties.put(EventConstants.EVENT_TOPIC, topics);
        return serviceProperties;
    }

    public void handleEvent(Event event) {
        if (event == null) {
            // 何もしない。
            return;
        }

        final Object originalEvent = event.getProperty(EventConstants.EVENT);
        if (originalEvent == null
                || (originalEvent instanceof BundleEvent) != true) {
            // 何もしない。
            return;
        }
        final BundleEvent bundleEvent = (BundleEvent) originalEvent;

        // 本当はThreadプールを使いたい。
        Thread notifyThread = new Thread("NOTITY THREAD(Twitter)") {
            public void run() {
                try {
                    notifyBundleEventByTwitter(bundleEvent);
                } catch (Throwable th) {
                    th.printStackTrace();
                }
            }
        };
        notifyThread.start();
    }

    private void notifyBundleEventByTwitter(BundleEvent bundleEvent) {
        Bundle eventSourceBundle = bundleEvent.getBundle();
        final String symbolicName = eventSourceBundle.getSymbolicName();
        final int bundleEventType = bundleEvent.getType();
        System.out.println(bundleEventTypeToString(bundleEventType) + ":" + symbolicName);

        // INSTALLED, STARTED, STOPPED, UPDATED, UNINSTALLEDの時だけbodyが入る。
        // これら以外のイベントの場合はnull
        final String tweet = createTweet(symbolicName, bundleEventType);

        if (tweet == null || tweet.trim().length() == 0) {
            return;
        }

        Properties twitterSettingProperties = getTwitterSettingProperties();

        if (twitterSettingProperties == null) {
            System.err.println("Could not get twitter setting.");
            return;
        }

        final String screenName = twitterSettingProperties.getProperty(PROP_KEY_SCREEN_NAME);
        final String password = twitterSettingProperties.getProperty(PROP_KEY_PASSWORD);

        TwitterFactory factory = new TwitterFactory();
        Twitter twitter = (Twitter) factory.getInstance(screenName, password);
        try {
            twitter.updateStatus(tweet);
        } catch (TwitterException e) {
            e.printStackTrace();
        }
    }

    private Properties getTwitterSettingProperties() {
        Properties properties = new Properties();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(PROP_FILE);
            properties.load(fis);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        if (properties.isEmpty() == true) {
            return null;
        }

        return properties;
    }

    private String createTweet(String symbolicName, int bundleEventType) {
        // INSTALLED, STARTED, STOPPED, UPDATED, UNINSTALLEDの時だけ処理する。
        // これら以外のイベントは処理しない。
        final String tweet;
        switch (bundleEventType) {
        case BundleEvent.INSTALLED:
            tweet = "Bundle-SymbolicNameが"
                + symbolicName + "のバンドルがインストールされました。";
            break;
        case BundleEvent.STARTED:
            tweet = "Bundle-SymbolicNameが"
                + symbolicName + "のバンドルがスタートしました。";
            break;
        case BundleEvent.STOPPED:
            tweet = "Bundle-SymbolicNameが"
                + symbolicName + "のバンドルがストップしました。";
            break;
        case BundleEvent.UPDATED:
            tweet = "Bundle-SymbolicNameが"
                + symbolicName + "のバンドルがアップデートされました。";
            break;
        case BundleEvent.UNINSTALLED:
            tweet = "Bundle-SymbolicNameが"
                + symbolicName + "のバンドルがアンインストールされました。";
            break;
        default:
            return null;
        }

        return tweet;
    }

    private static String bundleEventTypeToString(int bundleEventType) {
        switch (bundleEventType) {
        case BundleEvent.INSTALLED:
            return "INSTALLED";
        case BundleEvent.STARTED:
            return "STARTED";
        case BundleEvent.STOPPED:
            return "STOPPED";
        case BundleEvent.UPDATED:
            return "UPDATED";
        case BundleEvent.UNINSTALLED:
            return "UNINSTALLED";
        case BundleEvent.RESOLVED:
            return "RESOLVED";
        case BundleEvent.UNRESOLVED:
            return "UNRESOLVED";
        default:
            return "UNKNOWN_TYPE(" + bundleEventType + ")";
        }
    }

}
